# include "globals.h"

/**
  Function to create a node
  @ Param dest takes the Destination IP address
  @ Param next_hop takes the Mac Address of the Next Hop node
  @ Param ifindex takes the value of the interface index
  @ Param hop_count takes the value of Hop count towards the Destination
  @ Param timestamp takes the value of time when this node was created
  @ Return the created node
 */
node * 
make_node (
        char dest[INET_ADDRSTRLEN], 
        unsigned char next_hop[HW_ADDR_LEN], 
        int ifindex, 
        int hop_count,	
        struct timeval timestamp
        )
{

    node * n = (node *) malloc(sizeof(node));
    int i;

    strcpy(n->dest, dest);
    for(i = 0; i < HW_ADDR_LEN; i++)
    {
        n->next_hop[i] = next_hop[i];
    }
    n->ifindex = ifindex;
    n->hop_count = hop_count;
    n->timestamp = timestamp;
    return n;
}

/*
   Function to print the Routing table
   @ Param head takes the  pointer to the start of the Routing table
 */
void 
print_table(
        table * head
        )
{

    table * temp = head->next;
    char * ptr;
    int i = 0;
    int j;

    printf("\nRouting Table:-\n");
    printf("DESTINATION\tNEXT HOP\tINTERFACE NO\tHOP COUNT\tTIMESTAMP\n");
    while(temp != NULL)
    {
        printf("%s\t", temp->entry->dest);
        ptr = temp->entry->next_hop;
        j = HW_ADDR_LEN;
        do 
        {
            printf("%.2x%s", *ptr++ & 0xff, (j == 1) ? " " : ":");
        } while (--j > 0);

        printf("\t%d\t%d\t%u\n", temp->entry->ifindex, temp->entry->hop_count, temp->entry->timestamp.tv_sec );
        i++;
        temp = temp->next; 
    }
}

/*
   Function to add an entry in the Routing table
   @ Param head takes the pointer to the first entry in the Routing table
   @ Param n takes the entry to be added in the Routing table	
 */
void 
add_entry(
        table * head, 
        node * n
        )
{

    table * temp;
    table * new_row = (table *)malloc(sizeof(table));
    new_row->next = NULL;

    new_row->entry = n;
    if(head->next == NULL)
    {
        head->next = new_row;
    }
    else
    {
        temp = head->next;
        while(temp->next != NULL)
        {			
            temp = temp->next; 
        }
        temp->next = new_row;
    }

}

/*
   Function to remove an entry from the Routing Table	
   @ Param head takes the pointer to the first entry in the Routing table
   @ Param dest takes the IP address of the entry which is to be discarded from the Routing table
 */
void 
remove_entry(
        table * head, 
        char dest[INET_ADDRSTRLEN]
        )
{


    table * prev = NULL, * curr;

    if(head->next == NULL)
    {
        printf("Routing Table is Empty\n");
    }
    else
    {
        curr = head->next;
        while(curr != NULL)
        {			
            if(!strcmp(curr->entry->dest, dest))
            {
                if(prev != NULL)
                {
                    prev->next = curr->next;
                }
                else
                {
                    head->next = curr->next;
                }
                return;	
            }
            prev = curr;	
            curr = curr->next; 
        }
    }
}

/*
   Function to update a Routing table entry
   @ Param head takes the pointer to the first entry in the Routing table
   @ Param n takes the value of the node which is to be modified in the Routing table with n itself	
 */
void 
update_entry(
        table * head, 
        node * n
        )
{

    table * update_row = (table *)malloc(sizeof(table));
    table * prev = NULL, *curr;

    curr = head->next;
    update_row->entry = n;

    while(curr != NULL)	
    {

        if(!strcmp(curr->entry->dest, n->dest))
        {
            if(prev != NULL)
            {
                prev->next = update_row;
            }
            else
            {
                head->next = update_row;
            }

            update_row->next = curr->next;
            return;
        }

        prev = curr;	
        curr = curr->next; 
    }
}

/**
  Function to find an entry in the Routing table
  @ Param head takes the pointer to the first entry in the Routing table
  @ Param dest takes the value of the IP address to be searched in the Routing table
  Returns the entry if found or else returns NULL
 */
node * 
find_entry(
        table * head, 
        char dest[INET_ADDRSTRLEN]
        )
{

    table * temp = head->next;
    while(temp!= NULL)
    {
        if(!strcmp(temp->entry->dest, dest))
        {
            return temp->entry;
        }
        temp = temp->next;
    }
    return NULL;
}

broadcast_recv*
create_br(
        char src_id[],
        int br_id
        )
{
    broadcast_recv * newnode = (broadcast_recv*) malloc(sizeof(broadcast_recv));

    strcpy(newnode->source_id, src_id);
    newnode->broadcast_id = br_id;

    return newnode;
}

void
insert_bl(
        broadcast_recv* node_to_insert,
        broadcast_list* head
        )
{
    broadcast_list* newnode;
    broadcast_list* temp = 0;

    newnode = (broadcast_list *) malloc (sizeof(broadcast_list));
    newnode-> bl_link = 0;
    newnode-> bl_recv = node_to_insert;

    if (head->bl_link == 0)
    {
        //
        // Empty list.
        //

        head->bl_link = newnode;
        return;
    }

    temp = head->bl_link;

    //
    // Traverse to the end of the list.
    //

    while (temp->bl_link != NULL)
    {
        temp = temp->bl_link;
    }

    temp->bl_link = newnode;
}

/**
  Finds an entry in the list.

  @retun -1 on failure, 0 on success.
 */
int
find_bl(
        char src_id[],
        int br_id,
        broadcast_list * head
       )
{
    broadcast_list* temp = 0;

    if (head->bl_link == NULL)
    {
        return -1;
    }

    temp = head->bl_link;

    while (temp != NULL)
    {
        if (temp->bl_recv->broadcast_id == br_id &&
                strcmp(temp->bl_recv->source_id, src_id) == 0)
        {
            return 0;
        }

        temp = temp->bl_link;
    }

    return -1;
}

void 
add_client(
        cli_log * cli_info, 
        char * sun_path, 
        int flag, 
        int tmp_port
        )
{
    cli_log * new_row = (cli_log *) malloc(sizeof(cli_log));

    new_row->entry = (client_info*) malloc(sizeof(client_info));

    new_row->entry->cli_port = tmp_port;
    new_row->entry->per_flag = flag;
    gettimeofday(&new_row->entry->timestamp, NULL);
    strcpy(new_row->entry->sunpath, sun_path);
    new_row->next = NULL;

    if(cli_info->next == NULL)
    {
        cli_info->next = new_row;
    }
    else
    {
        cli_log * temp = cli_info->next;

        while(temp->next != NULL)
        {
            temp = temp->next;
        }

        temp->next = new_row;
    }
}

char * 
find_client_sunpath(
        cli_log * cli_info, 
        int port
        )
{
    cli_log * temp = cli_info->next;

    while(temp!=NULL)
    {
        if(temp->entry->cli_port == port)
        {
            return temp->entry->sunpath;
        }

        temp = temp->next;
    }

    return NULL;
}

int
find_client(
        cli_log * cli_info, 
        char * sun_path
        )
{
    cli_log * temp = cli_info->next;

    while(temp!=NULL)
    {
        if(strcmp(sun_path, temp->entry->sunpath) == 0)
        {
            return 1;
        }

        temp = temp->next;
    }

    return 0;
}

void 
delete_client(
        cli_log * cli_info, 
        int port
        )
{
    cli_log * curr;
    cli_log  * prev= NULL;

    if (cli_info->next == NULL)
    {
        return;
    }

    curr = cli_info->next;
    prev = curr;

    while(curr!=NULL)
    {
        if(curr->entry->cli_port == port)
        {
            prev->next = curr->next;
            free(curr);
            curr = NULL;
            return;
        }

        prev = curr;
        curr = curr->next;
    }
}

void
update_client(
        cli_log * cli_info, 
        char * sun_path
        )
{
    cli_log * temp;

    if (cli_info->next == NULL)
    {
        return;
    }

    temp = cli_info->next;

    while (temp!=NULL)
    {
        if(strcmp(sun_path, temp->entry->sunpath) == 0)
        {
            gettimeofday(&temp->entry->timestamp, NULL);
            break;
        }

        temp = temp->next;
    }
}

void
cleanup_client_table(
        cli_log* cli_info
        )
{
    cli_log* temp;
    cli_log* prev;
    struct timeval curr_time;

    if (cli_info->next == NULL)
    {
        printf("Empty client sunpath table.\n");
        return;
    }

    temp = cli_info->next;
    prev = temp;

    gettimeofday(&curr_time, NULL);

    while (temp != NULL)
    {
        if (temp->entry->per_flag == 1)
        {
            temp = temp->next;
            continue;
        }

        if (curr_time.tv_sec - temp->entry->timestamp.tv_sec > CLIENT_TIMEOUT + 1)
        {
            //
            // delete the node.
            //

            printf("Deleting %s\n", temp->entry->sunpath);

            if (temp->next == NULL)
            {
                //
                // I am the last node.
                //

                free(temp);
                prev->next = NULL;

                return;
            }
            else
            {
                //
                // Intermed node.
                //

                prev->next = temp->next;
                free(temp);
                temp = prev->next;
            }
        }

        prev = temp;
        temp = temp->next;
    }
}

void
print_client_table(
        cli_log* cli_info
        )
{
    cli_log* temp;

    if (cli_info->next == NULL)
    {
        printf("Empty Table.\n");
        return;
    }

    temp = cli_info->next;

    printf("CLIENT TABLE:\n");

    while (temp != NULL)
    {
        printf("SUN_PATH: [%s]\t\tTIMESTAMP: [%u]\n", temp->entry->sunpath,
                temp->entry->timestamp.tv_sec);

        temp = temp->next;
    }

    printf("\n");
}


